package br.uvv.sao.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import br.uvv.sao.domain.AlternativaBase;
import br.uvv.sao.domain.PalavraChave;
import br.uvv.sao.domain.Professor;
import br.uvv.sao.domain.QuestaoBase;
import br.uvv.sao.domain.Usuario;
import br.uvv.sao.enums.TipoGrauDificuldade;
import br.uvv.sao.util.DAOException;
import br.uvv.sao.util.HibernateUtil;

@SuppressWarnings("unchecked")
public class QuestaoDAO extends DAO {
	
	private static final long serialVersionUID = 4078178715546114279L;

	public Professor getProfessor(Usuario usuarioLogado) throws DAOException {
		Criterion[] filtro = {Restrictions.eq("id", usuarioLogado.getId())};
		String[] fetchMode = {"perfil"};
		return (Professor) get(Professor.class, fetchMode, filtro);
	}
	
	public PalavraChave getPalavraChave(String nome){
		Criterion[] filtro = {Restrictions.ilike("nome", nome)};
		String[] fetchMode = null;
		PalavraChave model;
		try {
			model = (PalavraChave) get(PalavraChave.class, fetchMode, filtro);
			if(modelNaoEhNulo(model)){
				return model;
			}else{
				model = new PalavraChave();
				model.setNome(nome);
				model.setVersion(0);
				this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
				this.transacao = this.sessao.beginTransaction();
				this.sessao.save(model);
				this.transacao.commit();
				return model;
			}
		} catch (DAOException e) {
			e.printStackTrace();
			return null;
		}
	}

	private boolean modelNaoEhNulo(PalavraChave model) {
		try {
			if(model.getId() > 0){
				return true;
			}else{
				return false;
			}
		} catch (NullPointerException e) {
			return false;
		}
	}

	public Integer findByObjectCount(String campo, String valor) {
		Integer count = 0;
		try{
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			Criteria filtro = this.sessao.createCriteria(PalavraChave.class);
			filtro.add(Restrictions.eq(campo, valor));
			count = filtro.list().size();
			this.transacao.commit();
		} catch(Throwable e){
			e.printStackTrace();
			if (this.transacao.isActive()){
				this.transacao.rollback();
			}
		} finally {
			try {
				if (this.sessao.isOpen()){
					this.sessao.close();
				}
			} catch (Throwable e){
				e.printStackTrace();
			}
		}
		return count;
	}

	public void salvar(PalavraChave palavraChaveInstance) {
		try{
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			this.sessao.save(palavraChaveInstance);
			this.transacao.commit();
		} catch(HibernateException e){
			System.out.println("H_ERRO - PalavraChave/Salvar: " + e.getMessage());
		} finally {
			try {
				if (this.sessao.isOpen()){
					this.sessao.close();
				}
			} catch (Throwable e){
				System.out.println("ERRO - PalavraChave/Salvar: " + e.getMessage());
			}
		}
	}

	public void atualizar(PalavraChave palavraChaveInstance) {
		try{
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			this.sessao.update(palavraChaveInstance);
			this.transacao.commit();
		} catch(HibernateException e){
			System.out.println("H_ERRO - PalavraChave/Atualizar: " + e.getMessage());
		} finally {
			try {
				if (this.sessao.isOpen()){
					this.sessao.close();
				}
			} catch (Throwable e){
				System.out.println("ERRO - PalavraChave/Atualizar: " + e.getMessage());
			}
		}
	}

	public void salvar(QuestaoBase questaoBaseInstance) {
		try{
			AlternativaBase correta = questaoBaseInstance.getAlternativaCorreta();
			ArrayList<AlternativaBase> alternativas = (ArrayList<AlternativaBase>) questaoBaseInstance.getAlternativas();
			questaoBaseInstance.setAlternativaCorreta(null);
			questaoBaseInstance.setAlternativas(null);
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			this.sessao.save(questaoBaseInstance);
			this.transacao.commit();
			
			
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			correta.setQuestaoBase(questaoBaseInstance);
			this.sessao.saveOrUpdate(correta);
			this.transacao.commit();
			
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			questaoBaseInstance.setAlternativaCorreta(correta);
			this.sessao.update(questaoBaseInstance);
			this.transacao.commit();
			
			for (AlternativaBase alternativaBase : alternativas) {
				this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
				this.transacao = this.sessao.beginTransaction();
				alternativaBase.setQuestaoBase(questaoBaseInstance);
				this.sessao.saveOrUpdate(alternativaBase);
				this.transacao.commit();
			}
		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	public void atualizar(QuestaoBase questaoBaseInstance, List<AlternativaBase> alternativaRemoverList) {
		try{
			AlternativaBase correta = questaoBaseInstance.getAlternativaCorreta();
			List<AlternativaBase> alternativas = questaoBaseInstance.getAlternativas();
			questaoBaseInstance.setAlternativaCorreta(null);
			questaoBaseInstance.setAlternativas(null);
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			this.sessao.update(questaoBaseInstance);
			this.transacao.commit();
			
			
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			correta.setQuestaoBase(questaoBaseInstance);
			this.sessao.saveOrUpdate(correta);
			this.transacao.commit();
			
			this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
			this.transacao = this.sessao.beginTransaction();
			questaoBaseInstance.setAlternativaCorreta(correta);
			this.sessao.update(questaoBaseInstance);
			this.transacao.commit();
			
			for (AlternativaBase alternativaBase : alternativas) {
				this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
				this.transacao = this.sessao.beginTransaction();
				alternativaBase.setQuestaoBase(questaoBaseInstance);
				this.sessao.saveOrUpdate(alternativaBase);
				this.transacao.commit();
			}
			
			for (AlternativaBase alternativaBase : alternativaRemoverList) {
				this.sessao = HibernateUtil.getSessionfactory().getCurrentSession();
				this.transacao = this.sessao.beginTransaction();
				this.sessao.delete(alternativaBase);
				this.transacao.commit();
			}
		} catch(HibernateException e){
			System.out.println("H_ERRO - QuestaoBase/Atualizar: " + e.getMessage());
		} finally {
			try {
				if (this.sessao.isOpen()){
					this.sessao.close();
				}
			} catch (Throwable e){
				System.out.println("ERRO - QuestaoBase/Atualizar: " + e.getMessage());
			}
		}
	}

	public List<QuestaoBase> listarQuestoes(int first, int pageSize,
			String sortField, boolean sortOrder, String variavelBusca, String varBuscaAssunto, String varBuscaCabecalho, TipoGrauDificuldade varBuscaDificuldade) throws DAOException {
		List<QuestaoBase> modelList = new ArrayList<QuestaoBase>();
		try {
			begin();
			Criteria criteria = sessao.createCriteria(QuestaoBase.class);
			criteria.add(Restrictions.ilike("codigo", "%" + variavelBusca + "%"));
			if(varBuscaAssunto != null && varBuscaAssunto != ""){
				criteria.createCriteria("palavraChave").add(Restrictions.ilike("nome", "%" + varBuscaAssunto + "%"));
			}
			criteria.add(Restrictions.ilike("cabecalho", "%" + varBuscaCabecalho + "%"));
			if(varBuscaDificuldade != null){
				criteria.add(Restrictions.eq("grauDificuldade", varBuscaDificuldade));
			}
			criteria.setFirstResult(first);
			criteria.setMaxResults(pageSize);
			if (sortField != null) {
					if (sortOrder){
						criteria.addOrder(Order.desc(sortField));
					} else { 
						criteria.addOrder(Order.asc(sortField));
					}
			} else {
			}
			modelList = criteria.list();
			commit();
		} catch (Exception e) {
			throw new DAOException(e);
		}
		return modelList;
	}

	public int listarQuestoesCount(String variavelBusca, String varBuscaAssunto, String varBuscaCabecalho, TipoGrauDificuldade varBuscaDificuldade) throws DAOException {
		Long count = 0L;
		try {
			begin();
			Criteria criteria = sessao.createCriteria(QuestaoBase.class);
			criteria.add(Restrictions.ilike("codigo", "%" + variavelBusca + "%"));
			if(varBuscaAssunto != null && varBuscaAssunto != ""){
				criteria.createCriteria("palavraChave").add(Restrictions.ilike("nome", "%" + varBuscaAssunto + "%"));
			}
			criteria.add(Restrictions.ilike("cabecalho", "%" + varBuscaCabecalho + "%"));
			if(varBuscaDificuldade != null){
				criteria.add(Restrictions.eq("grauDificuldade", varBuscaDificuldade));
			}
			criteria.setProjection(Projections.rowCount());
			count = (Long) criteria.uniqueResult();
			commit();
		} catch (Exception e) {
			throw new DAOException(e);
		}
		return Integer.parseInt(count.toString());
	}

	public QuestaoBase getQuestao(Long id) throws DAOException {
		String[] fetchMode = {"palavraChave", "professor", "alternativaCorreta", "alternativas"};
		return (QuestaoBase) get(QuestaoBase.class, id, fetchMode);
	}

	public void delete(QuestaoBase questaoBaseInstance) throws DAOException {
		delete(QuestaoBase.class, questaoBaseInstance.getId());
	}

}
